/**
 * Copyright (C) 2013-2014 the original author or authors.
 */
package com.foreveross.bsl.file.storage.local;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.StringUtils;

import com.foreveross.bsl.file.storage.FileStorage;
import com.google.common.io.Files;
import com.taobao.common.tfs.packet.FileInfo;

/**
 * xxx
 * 
 * @author Wangyi
 * @version v1.0
 * 
 * @date 2013-9-12
 * 
 */
public class LocalFileStorage implements FileStorage {

	private static final int MAX_FILE_NAME_LEN = 50;
	private static final int RANDOM_LEN = 16;

	private File basePath;

	public LocalFileStorage(File basePath) {
		if (basePath == null) {
			throw new IllegalArgumentException("basePath can not be null");
		}
		if (!basePath.exists()) {
			if (!basePath.mkdirs()) {
				throw new RuntimeException("make path " + basePath + " failed!");
			}
		}
		if (!basePath.isDirectory()) {
			throw new IllegalArgumentException("basePath must be a directory");
		}
		this.basePath = basePath;
	}

	private String genFilename() {
		return this.genFilename(null, null);
	}

	private String genFilename(String prefix, String suffix) {
		String random = RandomStringUtils.randomAlphanumeric(RANDOM_LEN);
		StringBuilder sb = new StringBuilder();
		if (!StringUtils.isEmpty(prefix)) {
			final int len = MAX_FILE_NAME_LEN - RANDOM_LEN - 1;
			if (prefix.length() >= len) {
				sb.append(prefix, 0, len);
			}
			sb.append(prefix).append('_');
		}
		sb.append(random);
		if (!StringUtils.isEmpty(suffix)) {
			if (!suffix.startsWith(".")) {
				sb.append('.');
			}
			sb.append(suffix);
		}
		return sb.toString();
	}

	private static class Filename {
		public String prefix;
		public String suffix;

		public Filename(String filename) {
			if (!StringUtils.isEmpty(filename)) {
				int index = filename.indexOf('.');
				if (index != -1) {
					prefix = filename.substring(0, index);
					suffix = filename.substring(index);
				} else {
					prefix = filename;
				}
			}
		}
	}

	public static void main(String[] args) {
		Filename fn = new Filename(".abc");
		System.out.println(fn.prefix);
		System.out.println(fn.suffix);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.foreveross.common.file.storage.FileStorage#saveFile(java.io.File)
	 */
	@Override
	public String saveFile(File file) throws IOException {
		Filename fn = new Filename(file.getName());
		File destFile = new File(this.basePath, this.genFilename(fn.prefix, fn.suffix));
		FileUtils.copyFile(file, destFile);
		return destFile.getName();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.foreveross.common.file.storage.FileStorage#saveFile(java.io.InputStream
	 * )
	 */
	@Override
	public String saveFile(InputStream in) throws IOException {
		File destFile = new File(this.basePath, this.genFilename());
		FileUtils.copyInputStreamToFile(in, destFile);
		return destFile.getName();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.foreveross.common.file.storage.FileStorage#saveFile(java.lang.String,
	 * java.lang.String, java.lang.String)
	 */
	@Override
	public String saveFile(String srcFileName, String destFileName, String suffix) throws IOException {
		File srcFile = new File(srcFileName);
		File destFile = new File(this.basePath, this.genFilename(destFileName, suffix));
		FileUtils.copyFile(srcFile, destFile);
		return destFile.getName();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.foreveross.common.file.storage.FileStorage#saveFile(byte[],
	 * java.lang.String, java.lang.String)
	 */
	@Override
	public String saveFile(byte[] data, String destFileName, String suffix) throws IOException {
		ByteArrayInputStream byteIs = new ByteArrayInputStream(data);
		File destFile = new File(this.basePath, this.genFilename(destFileName, suffix));
		FileUtils.copyInputStreamToFile(byteIs, destFile);
		return destFile.getName();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.foreveross.common.file.storage.FileStorage#saveLargeFile(java.lang
	 * .String, java.lang.String, java.lang.String)
	 */
	@Override
	public String saveLargeFile(String srcFileName, String destFileName, String suffix) throws IOException {
		File srcFile = new File(srcFileName);
		File destFile = new File(this.basePath, this.genFilename(destFileName, suffix));
		InputStream input = null;
		OutputStream output = null;
		try {
			input = new FileInputStream(srcFile);
			output = new FileOutputStream(destFile);
			IOUtils.copyLarge(input, output);
		} finally {
			IOUtils.closeQuietly(output);
			IOUtils.closeQuietly(input);
		}
		return destFile.getName();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.foreveross.common.file.storage.FileStorage#unlinkFile(java.lang.String
	 * , java.lang.String)
	 */
	@Override
	public boolean unlinkFile(String tfsFileName, String tfsSuffix) {
		//Nothing to do for local
		return false;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.foreveross.common.file.storage.FileStorage#fetchFile(java.lang.String
	 * , java.lang.String, java.lang.String)
	 */
	@Override
	public boolean fetchFile(String storedFileName, String suffix, String fetchedFileName) throws IOException{
		File storedFile=new File(this.basePath, storedFileName);
		File fetchedFile=new File(fetchedFileName);
		Files.createParentDirs(fetchedFile);
		FileUtils.copyFile(storedFile, fetchedFile);
		return true;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.foreveross.common.file.storage.FileStorage#fetchFile(java.lang.String
	 * , java.lang.String, java.io.OutputStream)
	 */
	@Override
	public boolean fetchFile(String storedFileName, String suffix, OutputStream output) throws IOException{
		File storedFile=new File(this.basePath, storedFileName);
		InputStream input=null;
		try{
			input=new FileInputStream(storedFile);
			IOUtils.copy(input, output);
		}finally{
			IOUtils.closeQuietly(input);
		}
		return true;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.foreveross.common.file.storage.FileStorage#destroy()
	 */
	@Override
	public void destroy() {
		//Nothing to do for local
	}
	
	/* (non-Javadoc)
	 * @see com.foreveross.common.file.storage.FileStorage#exists(java.lang.String)
	 */
	@Override
	public boolean exists(String storedFileName) {
		if(StringUtils.isEmpty(storedFileName)){
			return false;
		}
		return new File(this.basePath, storedFileName).exists();
	}
	
	/* (non-Javadoc)
	 * @see com.foreveross.common.file.storage.FileStorage#delete(java.lang.String)
	 */
	@Override
	public boolean delete(String storedFileName) {
		return new File(this.basePath, storedFileName).delete();
	}

    /* (non-Javadoc)
     * @see com.foreveross.common.file.storage.FileStorage#statFile(java.lang.String, java.lang.String)
	 */
	@Override
	public FileInfo statFile(String tfsFileName, String tfsSuffix) {
		// TODO Auto-generated method stub
		FileInfo fileInfo = new FileInfo();
		File storedFile=new File(this.basePath, tfsFileName);
		fileInfo.setLength(storedFile.length());
		return fileInfo;
	}

}